#include "Cliente.h"
bool Cliente::salir = false;

void Cliente::finalizar(){
	std::cout << "Finalizo todo el cliente\n";
	fifoServer.cerrar();
	Cliente::salir = true;
	kill(pidTeclado, SIGUSR1);
}

static void finalizarTeclado(int signal){
	Cliente::setSalida();
}

void Cliente::cambiarEstado(EstadoCliente* nuevo){
	if(estado != NULL)
		delete estado;
	estado = nuevo;
}

Cliente::~Cliente(){
	if(estado)
		delete estado;
}


void Cliente::procesarMensajes(){
	while(!salir){
		Mensaje m;
		fifo.leer(m.getBuffer(),m.size());

		int tipo = m.getTipo();
		if(tipo == MENSAJE_COMANDO){
			//Proceso la entrada de teclado
			estado->entradaTeclado(((MensajeComando*)&m)->getComando());
		}
		else if(tipo == MENSAJE_LISTA_JUGADORES || tipo == MENSAJE_LISTA_JUGADORES_FIN)
			estado->recibirListaJugadores(*(MensajeListaJugadores*)&m);
		else if(tipo == MENSAJE_INVITACION)
			estado->recibirInvitacion(*(MensajeInvitacion*)&m);
		else if(tipo == MENSAJE_TABLERO)
			estado->recibirTablero(*(MensajeTablero*)&m);
		else if(tipo == MENSAJE_NOTIFICACION)
			std::cout << ((MensajeNotificacion*)&m)->getMensaje() << "\nComando: " << std::flush;
		else if(tipo == MENSAJE_CEDER_TURNO)
			estado->recibirTurno();
		else if(tipo == MENSAJE_DISPARO)
			estado->recibirDisparo(*(MensajeDisparo*)&m);
		else if(tipo == MENSAJE_GANAR)
			estado->ganar();
		else if(tipo == MENSAJE_PERDER)
			estado->perder();
		else if(tipo == MENSAJE_COMENZAR_JUEGO)
			estado->comenzarJuego(*(MensajeComenzarJuego*)&m);
		else if(tipo == MENSAJE_DESCONECTAR){
			estado->recibirDesconeccion(*(MensajeDesconectar*)&m);
		}
	}
}

void Cliente::run(){
	salir = false;
	std::cout << "Ingrese su nombre de usuario: ";
	std::cin >> nombre;
	pidPrincipal = getpid();
	std::stringstream s;
	s << pidPrincipal;
	fifo.abrir(s.str().c_str());

	int pid=fork();
	if(pid==0){
		signal(SIGUSR1, finalizarTeclado);
		//Proceso el teclado
		procesarTeclado();
		exit(0);
	}
	pidTeclado=pid;


	fifoServer.abrir("FIFOSERVER");

	MensajeConectar m(nombre);
	enviarMensaje(m);

	estado = new Conectado(this);

	//Proceso los mensajes
	procesarMensajes();
	int status;
	wait(&status);
	
	fifo.borrar();
}


int main(){
	signal(SIGINT, SIG_IGN);
	signal(SIGTERM, SIG_IGN);

	try{
		Cliente c;
		c.run();
	}
	catch(GenericException &e){
		std::cout << "Excepcion: " << e.what() << "\n";
	}
}
